/*
 * @Author: Betty
 * @Date: 2021-01-16 22:37:58
 * @LastEditors: Betty
 * @LastEditTime: 2021-02-13 23:15:18
 * @Description: 一些通用的工具函数
 */

import { ImageProps, ColumnProps, UserProps } from './store'
export function generateFitUrl(data: ImageProps, width: number, height: number, format = ['m_pad']) {
  if (data && data.url) {
    const formatStr = format.reduce((prev, current) => {
      return current + ',' + prev
    }, '')
    data.fitUrl = data.url + `?x-oss-process=image/resize,${formatStr}h_${height},w_${width}`
  }
}

// 新增一个处理专栏或用户头像的函数
export function addColumnAvatar (data: ColumnProps | UserProps, width: number, height: number) {
  // 如果本身就有avatar，说明之前有上传过头像，那么就对头像进行处理，否则使用默认图，默认图也是根据类型判断
  if (data.avatar) {
    generateFitUrl(data.avatar, width, height)
  } else {
    // 区分专栏和作者类型，不能用instanceof和typeof，要用title属性
    const ParseCol = data as ColumnProps
    data.avatar = {
      fitUrl: require(ParseCol.title ? '@/assets/column.jpg' : '@/assets/avatar.jpg')
    }
  }
}

// 为条件定义类型，因为条件大同小异
interface CheckCondition {
  format?: string[];// 类型是字符串，可能不止支持一种类型，所以用数组
  size?: number;//数字类型，单位是M
}
// 定义错误类型，要么是具体哪种原因导致的错误，要么是没错
type ErrorType = 'size' | 'format' | null
// 定义上传之前检查文件类型的函数，参数为文件和条件
export function beforeUploadCheck(file: File, condition: CheckCondition) {
  // 1.把条件里的类型和大小解构出来
  const { format, size } = condition
  // 2.检查大小和类型是否符合要求,file.type和file.size属性能拿到文件的类型和大小
  const isValidFormat = format ? format.includes(file.type) : true
  const isValidSize = size ? (file.size / 1024 / 1024 < size) : true
  // 3.定义记录错误信息的值的变量，默认为null，无错误
  let error: ErrorType = null
  // 4.根据前面的结果，来决定是哪种错误
  if (!isValidFormat) {
    error = 'format'
  }
  if (!isValidSize) {
    error = 'size'
  }
  // 返回的是是否通过，以及错误原因
  return {
    passed: isValidSize && isValidFormat,
    error
  }
}

// 来定义一个测试数据类型
interface TestProps {
  _id: string;
  name: string;
}
// 定义一个测试类型的数组
const testData:TestProps[] = [
  {
    _id: '1',
    name: 'a'
  },
  {
    _id: '2',
    name: 'b'
  }
]
// 定义两个函数，实现数组与对象的互转
// 1.把数组转成对象
// 注意，我们输入的是可以遍历的“测试类型”数组，返回的也应该是可以索引的对象，索引的值也是“测试类型”的值
export const arrToObject = <T extends { _id?:string; }>(array: Array<T>) => {
  // reduce的第一个参数也是回调函数，回调函数的参数是“之前的结果”，“当前的值”，“当前的index”
  // 第二个参数是初始值
  return array.reduce((prev, current) => {
    // 给泛型加上约束，让它可能有id属性，这里就可以使用id属性了
    if(current._id){
      // prev表示的是之前的结果，也就是已经有一些那样属性的对象了，我们现在要给它加上新属性
      prev[current._id] = current
    }
    // 这里把我们改动后的对象返回，下一次会在这个基础上添加新属性
    return prev
  }, {} as { [key: string]: T}) // 这里的初值值是空对象没错，但是我们要声明它是一个有key属性的对象，key值不确定，属性值类型是泛型
}
// 因为我的参数是一个泛型数组，所以我传入参数后，就知道“泛型”现在具体是什么类型了，无需传入
const result = arrToObject(testData)
console.log(result) // 结果正确
// 定义一个哈希对象
// testData2的类型是一种对象，
// 这种对象里面有一些不确定的string类型的属性，我们把它当成一个个数据对应的key
// 每个key对应的值都是一个“测试类型”的对象
const testData2: {[key: string]: TestProps} = {
  '1': {
    _id: '1',
    name: 'a'
  },
  '2': {
    _id: '2',
    name: 'b'
  },
}
// 定义把对象转成数组的函数
export const objectToArr = <T>(obj: { [key: string]: T}) => {
  // 使用Object.keys方法，来得到属性名数组
  return Object.keys(obj).map(key => {
    // 然后遍历这个数组，把每个key对应的值作为数组对应的元素
    return obj[key]
  })
}
const result2 = objectToArr(testData2)
console.log(result2) // 结果正确